<template>
  <div class="driverPrgram">
    <el-dialog :title="drawerTitle" :visible.sync="dialogVisible" width="564px" @closed="handleClose">
      <el-form
        ref="formData"
        class="formContent"
        :model="formData"
        :rules="rules"
        label-suffix="："
        :label-width="formData.chipType === 1 ? '93px' : '149px'"
      >
        <el-form-item v-if="dialogType === 'add'" label="选择芯片" prop="chipId">
          <el-cascader
            v-model="formData.chipId"
            :options="formData.chipType === 1 ? chipData.masterChipList : chipData.slaveChipList"
            :props="props"
            separator="/"
            clearable
            style="width: 100%"
            placeholder="请选择芯片"
          />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button :loading="loading" @click="closeForm()">取 消</el-button>
        <el-button :loading="loading" type="primary" :disabled="disabledBtn" @click="submitForm">
          {{ dialogType === 'add' ? '确定添加' : '确定修改' }}
        </el-button>
      </span>
    </el-dialog>
    <el-drawer
      :with-header="false"
      :close-on-press-escape="false"
      :wrapper-closable="false"
      :visible.sync="drawerVisible"
      size="800px"
      @closed="handleClose"
    >
      <div class="drawerForm">
        <div class="pageTitle">
          <div class="titleText">{{ drawerTitle }}</div>
        </div>
        <el-form
          ref="formData"
          class="formContent"
          :model="formData"
          :rules="rules"
          label-suffix="："
          :label-width="formData.chipType === 1 ? '93px' : '149px'"
        >
          <el-form-item v-if="dialogType === 'add'" label="选择芯片" prop="chipId">
            <el-cascader
              v-model="formData.chipId"
              :options="formData.chipType === 1 ? chipData.masterChipList : chipData.slaveChipList"
              :props="props"
              separator="/"
              clearable
              style="width: 30%; margin-right: 20px"
              placeholder="请选择芯片"
            />
            <el-button type="primary" @click="handleDownload(2)">下载示例模板</el-button>
          </el-form-item>
          <el-form-item v-if="formData.chipType === 2 && dialogType === 'edit'" :label="'当前驱动定义文件'">
            <el-button type="primary" @click="handleDownload(1)">下载驱动定义文件</el-button>
          </el-form-item>
          <el-form-item
            v-if="formData.chipType === 2"
            :label="dialogType === 'add' ? '上传驱动定义文件' : '更新驱动定义文件'"
            prop="driverDefinitionFiles"
          >
            <el-upload
              ref="driverDefinitionFiles"
              class="upload-demo"
              action="#"
              :limit="uploadSetting.limit"
              :accept="uploadSetting.accept"
              :file-list="formData.driverDefinitionFiles"
              :on-exceed="handleExceed"
              :on-remove="() => handleRemove('driverDefinitionFiles')"
              :http-request="(require) => handleUploadFiles(require, 'driverDefinitionFiles')"
            >
              <div slot="tip" class="el-upload__tip">
                只能上传{{ uploadSetting.accept.split(',').join(' ') }}文件，且单个文件不超过 20 MB
              </div>
              <el-button size="small" plain>
                上传文件
                <i class="el-icon-upload el-icon--right" />
              </el-button>
            </el-upload>
          </el-form-item>
          <el-form-item v-if="formData.chipType === 2" label="文件规则检查">
            <div class="percentageBox">
              <el-progress
                :percentage="fileRulesCheckPercentage"
                :status="getPercentageStatus(fileRulesCheckResult)"
                :show-text="false"
              ></el-progress>
              <template v-if="fileRulesCheckResult === 'fail'">
                <i class="el-icon-circle-close failResult" />
                <el-button type="primary" class="downloadBtn" @click="handleView">查看检查结果</el-button>
              </template>
              <i v-else-if="fileRulesCheckResult === 'success'" class="el-icon-circle-check successResult" />
            </div>
          </el-form-item>

          <el-form-item
            v-if="formData.chipType === 2 && startParameterConfigurationRuleGeneration"
            label="参数配置规则生成"
          >
            <div class="percentageBox">
              <el-progress
                :percentage="parameterConfigurationRuleGenerationPercentage"
                :show-text="false"
                :status="getPercentageStatus(parameterConfigurationRuleGenerationResult)"
              ></el-progress>

              <template v-if="parameterConfigurationRuleGenerationResult === 'fail'">
                <i class="el-icon-circle-close failResult" />
              </template>
              <i
                v-else-if="parameterConfigurationRuleGenerationResult === 'success'"
                class="el-icon-circle-check successResult"
              />
            </div>
          </el-form-item>
        </el-form>

        <div class="drawerFooter" align="right">
          <el-button :loading="loading" @click="closeForm()">取 消</el-button>
          <el-button :loading="loading" type="primary" :disabled="disabledBtn" @click="submitForm">
            {{ dialogType === 'add' ? '确定添加' : '确定修改' }}
          </el-button>
        </div>
      </div>
    </el-drawer>
    <el-dialog
      :title="'参数配置规则'"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :show-close="false"
      :visible.sync="ruleDialogVisible"
      width="564px"
    >
      <el-table
        :height="500"
        :show-header="false"
        :data="parameterConfigurationRuleSetList"
        border
        style="width: 100%"
      >
        <el-table-column prop="ruleSetName" label="规则集名称">
          <template slot-scope="scope">{{ scope.row.ruleSetName }}规则集</template>
        </el-table-column>
        <el-table-column fixed="right" label="操作" width="100" align="center">
          <template slot-scope="scope">
            <el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button>
          </template>
        </el-table-column>
      </el-table>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="handleClose">关闭</el-button>
      </span>
    </el-dialog>
    <testResult ref="testResult" />
    <ruleSetDetail
      v-if="showRuleSetDetail"
      ref="ruleSetDetail"
      type="parameterConfigure"
      @close="showRuleSetDetail = false"
    />
  </div>
</template>

<script>
import { uploadFile } from '@/api/system-management'
import { addDriverLibrary, updateDriverLibraryByFile } from '@/api/project-management'
import { fileRuleCheck, initParameterConfiguration } from '@/api/rule-management'
import defaultSettings from '@/settings'
import testResult from './testResult'
import ruleSetDetail from '@/views/rule-management/components/ruleSetDetail.vue'
import { generateUUID, postMessage, receivedMessage } from '@/utils/index'
import { downLoadFile, downLoadFileFromServer, fileDownload } from '@/utils/download'

export default {
  name: 'DriverPrgram',
  components: { testResult, ruleSetDetail },
  inheritAttrs: false,
  props: {
    chipData: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  data() {
    return {
      disabledBtn: false,
      loading: false,
      dialogVisible: false,
      drawerVisible: false,
      uploadUrl: process.env.VUE_APP_BASE_API + 'vue/files/upload',
      formData: {
        chipType: 1,
        chipId: '',
        driverDefinitionFiles: []
      },
      drawerTitle: '',
      // 附件列表
      annexList: [],
      props: {
        label: 'label',
        value: 'value',
        children: 'children',
        emitPath: false
      },
      areaData: [],
      areaPlaceholder: '请选择',
      rules: {
        chipId: [{ required: true, message: '请选择芯片', trigger: ['change', 'blur'] }],
        driverDefinitionFiles: [
          { type: 'array', required: true, message: '请上传驱动定义文件', trigger: 'change' }
        ]
      },
      dialogType: '',
      uploadSetting: {
        limit: 1,
        accept: '.json'
      },
      masterChipArray: [],
      slaveChipArray: [],
      notPassDataList: [],
      ruleDialogVisible: false,
      fileRulesCheckResult: 'running',
      fileRulesCheckPercentage: 0,
      startParameterConfigurationRuleGeneration: false,
      parameterConfigurationRuleGenerationResult: 'running',
      parameterConfigurationRuleGenerationPercentage: 0,
      parameterConfigurationRuleSetList: [],
      showRuleSetDetail: false,
      conditionalRelationOption: [],
      uploadFileRequestId: generateUUID(),
      currentUploadFile: {},
      downloadFileRequestId: generateUUID(),
      addOrUpdateDriverLibraryRequestId: generateUUID(),
      fileRuleCheckRequestId: generateUUID(),
      initParameterConfigurationRequestId: generateUUID()
    }
  },
  mounted() {
    receivedMessage(this.dataHandle)
  },
  methods: {
    dataHandle(result) {
      let self = this
      let e = defaultSettings.isWPF ? result : { data: JSON.parse(result) }
      if (e.data.webInfo.requestId === self.uploadFileRequestId) {
        self.afterUpload(e.data.response)
      } else if (e.data.webInfo.requestId === self.downloadFileRequestId) {
        // const blob = new Blob([JSON.stringify(e.data.response, null, 2)], { type: 'text/plain;charset=utf-8' })
        // saveAs(blob, self.chipDefinitionFiles[0].fileName)
        let res = e.data.response
        if (res.success) {
          var bytes = new Uint8Array(
            window
              .atob(res.data)
              .split('')
              .map(function (c) {
                return c.charCodeAt(0)
              })
          )
          res.data = bytes
          fileDownload(res)
        } else {
          self.$message.error(res.message)
        }
      } else if (e.data.webInfo.requestId === self.addOrUpdateDriverLibraryRequestId) {
        self.afterAddOrUpdateDriver(e.data.response)
      } else if (e.data.webInfo.requestId === self.fileRuleCheckRequestId) {
        let res = e.data.response
        self.disabledBtn = false
        if (res.success) {
          self.timer && clearInterval(self.timer)
          self.notPassDataList = res.data.notPassDataList
          if (self.notPassDataList.length === 0) {
            self.fileRulesCheckResult = 'success'
            self.fileRulesCheckPercentage = 100
          } else {
            self.fileRulesCheckResult = 'fail'
          }
        } else {
          self.notPassDataList = []
          self.timer && clearInterval(self.timer)
          self.fileRulesCheckResult = 'fail'
        }
      } else if (e.data.webInfo.requestId === self.initParameterConfigurationRequestId) {
        let res = e.data.response
        if (res.success) {
          self.$nextTick(() => {
            self.$refs.ruleSetDetail.is('view', res.data)
          })
        } else {
          self.$message.error(res.message)
        }
      }
    },
    is(type, data) {
      this.startParameterConfigurationRuleGeneration = false
      this.fileRulesCheckResult = 'running'
      this.fileRulesCheckPercentage = 0
      this.parameterConfigurationRuleGenerationResult = 'running'
      this.parameterConfigurationRuleGenerationPercentage = 0
      this.loading = false
      if (data.chipType === 1) {
        this.dialogVisible = true
      } else {
        this.drawerVisible = true
      }
      this.dialogType = type
      this.formData = JSON.parse(JSON.stringify(data))
      this.$nextTick(() => {
        this.$refs.formData.clearValidate()
      })
      if (type === 'add') {
        this.drawerTitle = data.chipType === 1 ? '添加主控工程' : '添加驱动程序'
      } else {
        this.drawerTitle = '修改驱动定义文件'
      }
    },
    getPercentageStatus(status) {
      let result = ''
      switch (status) {
        case 'success':
          result = 'success'
          break
        case 'fail':
          result = 'exception'
          break
        default:
          result = undefined
      }
      return result
    },
    // 查看检查结果
    handleView() {
      this.$refs.testResult.is({
        chipDefinitionFiles: this.formData.driverDefinitionFiles,
        notPassDataList: this.notPassDataList
      })
    },
    handleClick(row) {
      this.showRuleSetDetail = true
      if (defaultSettings.isWPF || defaultSettings.isCEF) {
        this.initParameterConfigurationRequestId = generateUUID()
        let message = {
          RequestUrl: process.env.VUE_APP_URL + '/ruleSet/initParameterConfiguration',
          RequestMethod: 'POST',
          Headers: {
            contentType: 'application/json'
          },
          QueryParameter: {},
          RequestBody: { ruleSetId: row.ruleSetId },
          WebInfo: {
            requestId: this.initParameterConfigurationRequestId
          }
        }
        postMessage(message)
      } else {
        initParameterConfiguration({ ruleSetId: row.ruleSetId }).then((res) => {
          this.$nextTick(() => {
            this.$refs.ruleSetDetail.is('view', res.data)
          })
        })
      }
    },
    handleDownload(flag) {
      const data = {}
      if (flag === 1) {
        data.files = this.formData.historyDriverDefinitionFiles
      } else if (flag === 2) {
        data.files = [
          {
            fileName: 'slaveChipDriverTemplate.json',
            path: 'uploads/files/chipDriverTemplate/slaveChipDriverTemplate.json'
          }
        ]
      }
      if (defaultSettings.isWPF || defaultSettings.isCEF) {
        this.downloadFileRequestId = generateUUID()
        let message = {
          RequestUrl: process.env.VUE_APP_URL + '/files/download',
          RequestMethod: 'POST',
          Headers: {
            contentType: 'application/json'
          },
          QueryParameter: {},
          RequestBody: { files: data.files },
          WebInfo: {
            requestId: this.downloadFileRequestId
          }
        }
        postMessage(message)
      } else {
        if (flag === 1) {
          downLoadFile(
            process.env.VUE_APP_BASE_API + this.formData.historyDriverDefinitionFiles?.[0]?.path,
            this.formData.historyDriverDefinitionFiles?.[0]?.fileName
          )
        } else if (flag === 2) {
          downLoadFileFromServer(data).then((res) => {
            // console.log(res)
            if (res.data != null && res.data != '') {
              const text = JSON.stringify(res.data, null, 2)
              const blob = new Blob([text], { type: 'text/plain;charset=utf-8' })
              const url = window.URL.createObjectURL(blob)
              const a = document.createElement('a')
              a.href = url
              a.download = 'slaveChipDriverTemplate.json'
              document.body.appendChild(a)
              a.click()
              document.body.removeChild(a)
              URL.revokeObjectURL(url)
            } else {
              this.$message.error('服务器找不到模板文件或文件内容异常,请询问管理员')
            }
          })
        } else {
          this.$message.error('函数执行异常')
        }
      }
    },
    handleExceed(files) {
      this.$refs.driverDefinitionFiles.clearFiles()
      this.handleUploadFiles({ file: files[0] }, 'driverDefinitionFiles')
    },
    // 上传前校验
    handleCheck(params, fileName) {
      var suffix = params.file.name.substring(params.file.name.lastIndexOf('.')) // .txt
      const isLimit = params.file.size / 1024 / 1024 < 20
      if (this.uploadSetting.accept.includes(suffix)) {
        if (!isLimit) {
          this.$notify.error('上传文件大小不能超过 20MB!')
          return false
        } else {
          return true
        }
      } else {
        this.$notify.error('上传文件不符合上传格式!')
        return false
      }
    },
    // 图片上传
    handleUploadFiles(require, fileName) {
      this.disabledBtn = true
      this.fileRulesCheckPercentage = 10
      this.fileRulesCheckResult = 'running'
      this.parameterConfigurationRuleGenerationPercentage = 0
      this.parameterConfigurationRuleGenerationResult = 'running'

      let fileDom = this.$refs[fileName].uploadFiles
      let uploadFilesLast = fileDom.length - 1
      let check = this.handleCheck(require, fileName)
      if (!check) {
        fileDom.splice(uploadFilesLast, 1)
        return
      }
      this.currentUploadFile = { require, fileName }
      if (defaultSettings.isWPF || defaultSettings.isCEF) {
        let self = this
        this.uploadFileRequestId = generateUUID()
        let reader = new FileReader() // new一个FileReader实例
        reader.readAsDataURL(require.file)
        reader.onload = function () {
          //   读取文件获得的对象
          let message = {
            RequestUrl: process.env.VUE_APP_URL + '/files/upload',
            RequestMethod: 'POST',
            Headers: {
              // contentType: 'multipart/form-data'
              contentType: 'application/json'
            },
            QueryParameter: {},
            RequestBody: {
              fileName: require.file.name,
              fileContent: reader.result.split(',')[1]
            },
            WebInfo: {
              requestId: self.uploadFileRequestId
            }
          }
          postMessage(message)
        }
      } else {
        let formData = new FormData()
        formData.append('file', require.file)
        uploadFile(formData)
          .then((res) => {
            this.afterUpload(res)
          })
          .catch(() => {
            fileDom.splice(uploadFilesLast, 1)
            this.$notify.error('上传失败')
          })
      }
    },
    afterUpload(res) {
      this.formData[this.currentUploadFile.fileName] = [
        {
          uid: this.currentUploadFile.require.file.uid,
          fileType: res.data.fileType,
          name: res.data.name,
          fileName: res.data.name,
          url: res.data.url,
          path: res.data.url,
          base64: 'data:image/png;base64,' + res.data.base64
        }
      ]
      this.$refs.formData.validateField(this.currentUploadFile.fileName)
      this.notPassDataList = []
      this.timer = setInterval(() => {
        this.fileRulesCheckPercentage += 10
        if (this.fileRulesCheckPercentage === 90) {
          this.timer && clearInterval(this.timer)
        }
      }, 50)
      if (defaultSettings.isWPF || defaultSettings.isCEF) {
        this.fileRuleCheckRequestId = generateUUID()
        let message = {
          RequestUrl: process.env.VUE_APP_URL + '/chip/fileRuleCheck',
          RequestMethod: 'POST',
          Headers: {
            contentType: 'application/json'
          },
          QueryParameter: {},
          RequestBody: {
            filePath: res.data.url,
            ruleSetType: 3
          },
          WebInfo: {
            requestId: this.fileRuleCheckRequestId
          }
        }
        postMessage(message)
      } else {
        fileRuleCheck({
          filePath: res.data.url,
          ruleSetType: 3
        })
          .then((res) => {
            this.timer && clearInterval(this.timer)
            this.notPassDataList = res.data.notPassDataList
            if (this.notPassDataList.length === 0) {
              this.fileRulesCheckResult = 'success'
              this.fileRulesCheckPercentage = 100
            } else {
              this.fileRulesCheckResult = 'fail'
            }
          })
          .catch(() => {
            this.notPassDataList = []
            this.timer && clearInterval(this.timer)
            this.fileRulesCheckResult = 'fail'
          })
          .finally(() => {
            this.disabledBtn = false
          })
      }
    },
    handleRemove(fileName) {
      this.fileRulesCheckPercentage = 0
      this.fileRulesCheckResult = 'running'
      this.parameterConfigurationRuleGenerationPercentage = 0
      this.parameterConfigurationRuleGenerationResult = 'running'
      this.formData[fileName] = []
    },
    handleClose() {
      this.$refs.driverDefinitionFiles?.clearFiles()
      this.ruleDialogVisible = false
      this.drawerVisible = false
    },
    closeForm() {
      this.drawerVisible = false
      this.dialogVisible = false
      this.$emit('closeForm')
    },
    submitForm() {
      if (this.fileRulesCheckResult === 'fail') {
        this.$notify.error('驱动定义文件未通过文件规则检查')
        return
      }
      this.$refs['formData'].validate((valid) => {
        if (valid) {
          this.startParameterConfigurationRuleGeneration = true
          this.loading = true
          if (this.formData.chipType === 2) {
            this.timer = setInterval(() => {
              this.parameterConfigurationRuleGenerationPercentage += 10
              if (this.parameterConfigurationRuleGenerationPercentage === 90) {
                this.timer && clearInterval(this.timer)
              }
            }, 200)
          }
          let params = {}
          if (this.dialogType === 'add') {
            params.chipType = this.formData.chipType
            params.chipId = this.formData.chipId
            if (this.formData.chipType === 2) {
              params.driverDefinitionFiles = this.formData.driverDefinitionFiles.map((item) => {
                return { ...item, base64: '' }
              })
            }
          } else {
            params.driverLibraryId = this.formData.driverLibraryId
            params.driverDefinitionFiles = this.formData.driverDefinitionFiles.map((item) => {
              return { ...item, base64: '' }
            })
          }
          // 新增和修改
          if (defaultSettings.isWPF || defaultSettings.isCEF) {
            this.addOrUpdateDriverLibraryRequestId = generateUUID()
            let message = {
              RequestUrl:
                process.env.VUE_APP_URL +
                (this.dialogType === 'add' ? '/driverLibrary/add' : '/driverLibrary/updateByFile'),
              RequestMethod: 'POST',
              Headers: {
                contentType: 'application/json'
              },
              QueryParameter: {},
              RequestBody: params,
              WebInfo: {
                requestId: this.addOrUpdateDriverLibraryRequestId
              }
            }
            postMessage(message)
          } else {
            let operation = this.dialogType === 'add' ? addDriverLibrary : updateDriverLibraryByFile
            operation(params)
              .then((res) => {
                this.afterAddOrUpdateDriver(res)
              })
              .catch(() => {
                this.loading = false
                this.timer && clearInterval(this.timer)
                this.parameterConfigurationRuleGenerationResult = 'fail'
              })
          }
        }
      })
    },
    afterAddOrUpdateDriver(res) {
      this.loading = false
      this.timer && clearInterval(this.timer)
      if (res.success) {
        if (this.formData.chipType === 1) {
          this.$message.success('添加主控工程成功')
        } else {
          this.$notify.success(this.dialogType === 'add' ? '添加驱动程序成功' : '修改驱动定义文件成功')
        }

        if (this.formData.chipType === 2) {
          this.ruleDialogVisible = true
          this.parameterConfigurationRuleSetList = res.data
          this.parameterConfigurationRuleGenerationResult = 'success'
          this.parameterConfigurationRuleGenerationPercentage = 100
        } else {
          this.closeForm()
        }
        this.$emit('submit', this.formData.chipType)
      } else {
        this.parameterConfigurationRuleGenerationResult = 'fail'
        if (this.formData.chipType === 1) {
          this.$message.error(res.message)
        } else {
          this.$notify.error(res.message)
        }
      }
    }
  }
}
</script>

<style lang="less" scoped>
.drawerForm {
  display: flex;
  flex-direction: column;
  height: 100%;
  .pageTitle {
    padding: 15px;
    font-size: 16px;
    color: #333;
    font-weight: bold;
    .titleText {
      display: inline;
      padding-right: 20px;
      padding-left: 5px;
    }
  }
  .formContent {
    height: calc(100% - 100px);
    margin: 0px 20px;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    padding-right: 7px;

    .percentageBox {
      height: 32px;
      display: flex;
      padding-right: 5px;
      align-items: center;
      .el-progress {
        flex: 1;
        padding-right: 10px;
      }
      .successResult {
        color: #67c23a;
      }
      .failResult {
        color: #f56c6c;
      }
      .downloadBtn {
        margin-left: 10px;
        // padding-right: 0;
      }
    }
  }
  .drawerFooter {
    padding: 0 20px;
    float: right;
  }
}
</style>
